﻿using Microsoft.Extensions.Configuration;
using ServiceStack.Text;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using Tauren.File.Entity.Config;

namespace Tauren.File.Infrastructure.RedisHelpe
{
    /// <summary>
    /// Redis读写帮助类
    /// </summary>
    public class RedisClient : IRedisClient
    {
        /// <summary>
        /// 读取配置文件
        /// </summary>
        private ApiVersionsConfig ApiConfig { get; set; }
        /// <summary>
        /// Redis 数据集
        /// </summary>
        private IDatabase db { get; set; }
        private ConnectionMultiplexer redis { get; set; }

        public RedisClient(IConfiguration configuration)
        {
            ApiConfig = configuration.Get<ApiVersionsConfig>();
            try
            {
                if (!string.IsNullOrEmpty(ApiConfig.RedisPwd))
                {
                    redis = ConnectionMultiplexer.Connect($"{ApiConfig.RedisAdress}:{ApiConfig.RedisPort},password={ApiConfig.RedisPwd}");
                }
                else
                {
                    redis = ConnectionMultiplexer.Connect($"{ApiConfig.RedisAdress}:{ApiConfig.RedisPort}");
                }
                if (redis is null) db = null; //throw new Exception("缓存服务器还未准备好,请联系管理员!");
                db = redis.GetDatabase();
            }
            catch (Exception ex)
            {
                db = null;// throw new Exception("缓存服务器还未准备好,请联系管理员!");
            }

        }
        #region string 类型操作
        /// <summary>
        /// 设置字符串数据
        /// </summary>
        /// <param name="Key">缓存key</param>
        /// <param name="Content">内容</param>
        /// <returns></returns>
        public bool SetStringValue(string Key, string Content)
        {
            return db.StringSet(Key, Content);
        }

        /// <summary>
        /// 保存单个key value
        /// </summary>
        /// <param name="key">Redis Key</param>
        /// <param name="value">保存的值</param>
        /// <param name="expiry">过期时间</param>
        /// <returns></returns>
        public bool SetStringKey(string Key, string Content, TimeSpan? Expiry = default(TimeSpan?))
        {
            return db.StringSet(Key, Content, Expiry);
        }
        /// <summary>
        /// 获取一个对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public T GetStringKey<T>(string Key) where T : class
        {
            var res = db.StringGet(Key);
            if (!res.IsNull)
                return JsonSerializer.DeserializeFromString<T>(res);
            return null;
        }
        /// <summary>
        ///  获取一个字符串对象
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public string GetStringValue(string Key)
        {
            return db.StringGet(Key);
        }

        /// <summary>
        /// 根据Key删除数据
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool DeleteStringKey(string Key)
        {
            return db.KeyDelete(Key);
        }
        #endregion

        #region HASH类型封装
        /// <summary>
        /// 判断该字段是否存在 hash 中
        /// </summary>
        /// <param name="redisKey"></param>
        /// <param name="hashField"></param>
        /// <returns></returns>
        public bool HashExists(string redisKey, string hashField)
        {
            if (db is null) return true;
            return db.HashExists(redisKey, hashField);
        }

        /// <summary>
        /// 从 hash 中移除指定字段
        /// </summary>
        /// <param name="redisKey"></param>
        /// <param name="hashField"></param>
        /// <returns></returns>
        public bool HashDelete(string redisKey, string hashField)
        {
            if (db is null) return true;
            return db.HashDelete(redisKey, hashField);
        }

        /// <summary>
        /// 从 hash 中移除指定字段（多个删除）
        /// </summary>
        /// <param name="redisKey"></param>
        /// <param name="hashField"></param>
        /// <returns></returns>
        public long HashDelete(string redisKey, IEnumerable<RedisValue> hashField)
        {
            if (db is null) return 0;
            return db.HashDelete(redisKey, hashField.ToArray());
        }

        /// <summary>
        /// 在 hash 设定值
        /// </summary>
        /// <param name="redisKey"></param>
        /// <param name="hashField"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool HashSet(string redisKey, string hashField, string value)
        {
            if (db is null) return true;
            return db.HashSet(redisKey, hashField, value);
        }

        /// <summary>
        /// 在 hash 中设定值（多个）
        /// </summary>
        /// <param name="redisKey"></param>
        /// <param name="hashFields"></param>
        public void HashSet(string redisKey, IEnumerable<HashEntry> hashFields)
        {
            if (db != null)
                db.HashSet(redisKey, hashFields.ToArray());
        }

        /// <summary>
        /// 在 hash 中获取值
        /// </summary>
        /// <param name="redisKey"></param>
        /// <param name="hashField"></param>
        /// <returns></returns>
        public RedisValue HashGet(string redisKey, string hashField)
        {
            if (db is null) return "";
            return db.HashGet(redisKey, hashField);
        }

        /// <summary>
        /// 在 hash 中获取值（多个）
        /// </summary>
        /// <param name="redisKey"></param>
        /// <param name="hashField"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public RedisValue[] HashGet(string redisKey, RedisValue[] hashField)
        {
            if (db is null) return null;
            return db.HashGet(redisKey, hashField);
        }

        /// <summary>
        /// 从 hash 返回所有的字段值
        /// </summary>
        /// <param name="redisKey"></param>
        /// <returns></returns>
        public IEnumerable<RedisValue> HashKeys(string redisKey)
        {
            if (db is null) return null;
            return db.HashKeys(redisKey);
        }

        /// <summary>
        /// 返回 hash 中的所有值
        /// </summary>
        /// <param name="redisKey"></param>
        /// <returns></returns>
        public RedisValue[] HashValues(string redisKey)
        {
            if (db is null) return null;
            return db.HashValues(redisKey);
        }

        /// <summary>
        /// 在 hash 设定值（序列化）
        /// </summary>
        /// <param name="redisKey"></param>
        /// <param name="hashField"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool HashSet<T>(string redisKey, string hashField, T value)
        {
            if (db is null) return true;
            var json = JsonSerializer.SerializeToString(value);
            return db.HashSet(redisKey, hashField, json);
        }

        /// <summary>
        /// 在 hash 中获取值（反序列化）
        /// </summary>
        /// <param name="redisKey"></param>
        /// <param name="hashField"></param>
        /// <returns></returns>
        public T HashGet<T>(string redisKey, string hashField)
        {
            if (db is null) return default(T);
            return JsonSerializer.DeserializeFromString<T>(db.HashGet(redisKey, hashField));
        }
        #endregion

        #region List类型方法封装
        /// <summary>
        /// 移除并返回存储在该键列表的第一个元素
        /// </summary>
        /// <param name="redisKey"></param>
        /// <returns></returns>
        public string ListLeftPop(string redisKey)
        {
            if (db is null) return "";
            return db.ListLeftPop(redisKey);
        }

        /// <summary>
        /// 移除并返回存储在该键列表的最后一个元素
        /// </summary>
        /// <param name="redisKey"></param>
        /// <returns></returns>
        public string ListRightPop(string redisKey)
        {
            if (db is null) return "";
            return db.ListRightPop(redisKey);
        }

        /// <summary>
        /// 移除列表指定键上与该值相同的元素
        /// </summary>
        /// <param name="redisKey"></param>
        /// <param name="redisValue"></param>
        /// <returns></returns>
        public long ListRemove(string redisKey, string redisValue)
        {
            if (db is null) return default(long);
            return db.ListRemove(redisKey, redisValue);
        }

        /// <summary>
        /// 在列表尾部插入值。如果键不存在，先创建再插入值
        /// </summary>
        /// <param name="redisKey"></param>
        /// <param name="redisValue"></param>
        /// <returns></returns>
        public long ListRightPush(string redisKey, string redisValue)
        {
            if (db is null) return default(long);
            return db.ListRightPush(redisKey, redisValue);
        }

        /// <summary>
        /// 在列表头部插入值。如果键不存在，先创建再插入值
        /// </summary>
        /// <param name="redisKey"></param>
        /// <param name="redisValue"></param>
        /// <returns></returns>
        public long ListLeftPush(string redisKey, string redisValue)
        {
            if (db is null) return default(long);
            return db.ListLeftPush(redisKey, redisValue);
        }

        /// <summary>
        /// 返回列表上该键的长度，如果不存在，返回 0
        /// </summary>
        /// <param name="redisKey"></param>
        /// <returns></returns>
        public long ListLength(string redisKey)
        {
            if (db is null) return default(long);
            return db.ListLength(redisKey);
        }

        /// <summary>
        /// 返回在该列表上键所对应的元素
        /// </summary>
        /// <param name="redisKey"></param>
        /// <returns></returns>
        public IEnumerable<RedisValue> ListRange(string redisKey)
        {
            if (db is null) return null;
            return db.ListRange(redisKey);
        }

        /// <summary>
        /// 返回在该列表上键所对应的元素
        /// </summary>
        /// <param name="redisKey">开始行</param>
        /// <param name="startRow">结束行</param>
        /// <returns></returns>
        public IEnumerable<RedisValue> ListRange(string redisKey, int startRow, int endRow)
        {
            if (db is null) return null;
            return db.ListRange(redisKey, startRow, endRow);
        }

        /// <summary>
        /// 移除并返回存储在该键列表的第一个元素
        /// </summary>
        /// <param name="redisKey"></param>
        /// <returns></returns>
        public T ListLeftPop<T>(string redisKey)
        {
            if (db is null) return default(T);
            return JsonSerializer.DeserializeFromString<T>(db.ListLeftPop(redisKey));
        }

        /// <summary>
        /// 移除并返回存储在该键列表的最后一个元素
        /// </summary>
        /// <param name="redisKey"></param>
        /// <returns></returns>
        public T ListRightPop<T>(string redisKey)
        {
            if (db is null) return default(T);
            return JsonSerializer.DeserializeFromString<T>(db.ListRightPop(redisKey));
        }

        /// <summary>
        /// 在列表尾部插入值。如果键不存在，先创建再插入值
        /// </summary>
        /// <param name="redisKey"></param>
        /// <param name="redisValue"></param>
        /// <returns></returns>
        public long ListRightPush<T>(string redisKey, T redisValue)
        {
            if (db is null) return default(long);
            return db.ListRightPush(redisKey, JsonSerializer.SerializeToString(redisValue));
        }

        /// <summary>
        /// 在列表头部插入值。如果键不存在，先创建再插入值
        /// </summary>
        /// <param name="redisKey"></param>
        /// <param name="redisValue"></param>
        /// <returns></returns>
        public long ListLeftPush<T>(string redisKey, T redisValue)
        {
            if (db is null) return default(long);
            return db.ListLeftPush(redisKey, JsonSerializer.SerializeToString(redisValue));
        }
        #endregion
        #region SortedSet类型方法封装
        /// <summary>
        /// SortedSet 新增
        /// </summary>
        /// <param name="redisKey"></param>
        /// <param name="member"></param>
        /// <param name="score"></param>
        /// <returns></returns>
        public bool SortedSetAdd(string redisKey, string member, double score)
        {
            if (db is null) return true;
            return db.SortedSetAdd(redisKey, member, score);
        }

        /// <summary>
        /// 在有序集合中返回指定范围的元素，默认情况下从低到高。
        /// </summary>
        /// <param name="redisKey"></param>
        /// <returns></returns>
        public IEnumerable<RedisValue> SortedSetRangeByRank(string redisKey)
        {
            if (db is null) return null;
            return db.SortedSetRangeByRank(redisKey);
        }

        /// <summary>
        /// 返回有序集合的元素个数
        /// </summary>
        /// <param name="redisKey"></param>
        /// <returns></returns>
        public long SortedSetLength(string redisKey)
        {
            if (db is null) return default(long);
            return db.SortedSetLength(redisKey);
        }

        /// <summary>
        /// 返回有序集合的元素个数
        /// </summary>
        /// <param name="redisKey"></param>
        /// <param name="memebr"></param>
        /// <returns></returns>
        public bool SortedSetLength(string redisKey, string memebr)
        {
            if (db is null) return true;
            return db.SortedSetRemove(redisKey, memebr);
        }

        /// <summary>
        /// SortedSet 新增
        /// </summary>
        /// <param name="redisKey"></param>
        /// <param name="member"></param>
        /// <param name="score"></param>
        /// <returns></returns>
        public bool SortedSetAdd<T>(string redisKey, T member, double score)
        {
            if (db is null) return default(bool);
            var json = JsonSerializer.SerializeToString(member);

            return db.SortedSetAdd(redisKey, json, score);
        }
        #endregion

        /// <summary>
        /// 设置 Key 的时间
        /// </summary>
        /// <param name="redisKey"></param>
        /// <param name="expiry"></param>
        /// <returns></returns>
        public bool KeyExpire(string RedisKey, TimeSpan? Expiry)
        {
            if (db is null) return true;
            return db.KeyExpire(RedisKey, Expiry);
        }
        /// <summary>
        /// 重命名 Key
        /// </summary>
        /// <param name="redisKey"></param>
        /// <param name="redisNewKey"></param>
        /// <returns></returns>
        public bool Rename(string redisKey, string redisNewKey)
        {
            if (db is null) return true;
            return db.KeyRename(redisKey, redisNewKey);
        }
        /// <summary>
        /// 将对象存储到redis
        /// </summary>
        /// <param name="Key"></param>
        /// <param name="Content"></param>
        /// <returns></returns>
        public bool SetStringValue(string Key, object Content)
        {
            if (db is null) return true;
            return db.StringSet(Key, JsonSerializer.SerializeToString(Content));
        } 
    }
}
